/**
 * 这个demo相当于是参数客户端，用于修改参数服务器中的参数
 *
 * 编译：colcon build --packages-select param_example
 * 环境配置：source ./install/setup.bash
 * 运行：ros2 run param_example simple_param_client
 */

#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/parameter_client.hpp"

class ParameterClient : public rclcpp::Node
{
public:
    ParameterClient() : Node("parameter_client")
    {
        // 创建异步参数客户端， 连接到名为 "simple_param"的节点
        parameters_client_ = std::make_shared<rclcpp::AsyncParametersClient>(this, "simple_param");

        // 检查服务器是否可用
        if (!parameters_client_->wait_for_service(std::chrono::seconds(5)))
        {
            RCLCPP_INFO(this->get_logger(), "参数服务器不可用");
            return;
        }

        // 设置参数
        set_parameters();
    }

private:
    std::shared_ptr<rclcpp::AsyncParametersClient> parameters_client_; // 异步参数客户端

    void set_parameters()
    {
        // 定义参数列表，准备发送给目标节点
        std::vector<rclcpp::Parameter> parameters;
        parameters.push_back(rclcpp::Parameter("k", 20.0));        // 设置参数"k"的值为20.0
        parameters.push_back(rclcpp::Parameter("max_speed", 5.0)); // 设置参数 "max_speed"的值为5.0

        // 异步发送设置参数的请求
        auto set_parameters_result = parameters_client_->set_parameters(parameters);
        RCLCPP_INFO(this->get_logger(), "请求发送，正在等待服务器响应...");

        // 处理响应结果（不是发送必须，只是用来接收消息查看）
        try
        {
            auto future = set_parameters_result;
            if (future.wait_for(std::chrono::seconds(5)) == std::future_status::timeout)
            {
                RCLCPP_ERROR(this->get_logger(), "设置参数超时");
            }
            else
            {
                auto results = future.get(); // 等待结果
                for (size_t i = 0; i < results.size(); ++i)
                {
                    if (results[i].successful)
                    {
                        RCLCPP_INFO(this->get_logger(), "参数 %s 更新成功", parameters[i].get_name().c_str());
                    }
                    else
                    {
                        RCLCPP_WARN(this->get_logger(), "参数 %s 更新失败", parameters[i].get_name().c_str());
                    }
                }
            }
        }
        catch (const std::exception &e)
        {
            RCLCPP_ERROR(this->get_logger(), "设置参数时发生错误: %s", e.what());
        }
    }
};

int main(int argc, char **argv)
{
    rclcpp::init(argc, argv);
    // rclcpp::spin(std::make_shared<ParameterClient>());   // 方式一：结束不终止
    auto client = std::make_shared<ParameterClient>(); // 方式二：结束终止
    rclcpp::shutdown();
    return 0;
}
